function Network(containerId, callback, custom) {
    // Custom Node style defined here
    $jit.ForceDirected.Plot.NodeTypes.implement({  
        'coralNode': {
            'render': function(node, canvas){
                var pos = node.pos.getc(true), 
                    dim,
	                width  = node.getData('width'),
	                height = node.getData('height'),
	                x = pos.x, y = pos.y,
	                ctx = canvas.getCtx(),
	                data = node.data;

		    	// node diameter calculation 
		    	var MAX = 20;
		    	var paperNum = node.getData('paperNums');
		    	dim = Math.floor(paperNum * 10 / MAX);
		    	node.setData('dim', dim);
		    	if(node.getData('selected') == 1)
		    		window.alert(" ");
			
		    	// node color calculation and node rendering
		    	var positive = node.getData('positive'), negative = node.getData('negative'), neutral = node.getData('neutral');
		    	var positiveIndex = positive / (positive + negative + neutral);
		    	var negativeIndex = negative / (positive + negative + neutral);
		    	var neutralIndex = neutral / (positive + negative + neutral);
		    	ctx.restore();
		    	ctx.save();
		    	ctx.beginPath();  
    
		    	ctx.arc(x, y, dim, 0, Math.PI * 2, true);

			////////////////////////////////////////////////////
			// !!! formulars for the colors here. Modify the calculation here.
		    	var greenIndex = Math.floor(255 * (positiveIndex + neutralIndex));
		    	var redIndex = Math.floor(255 * (negativeIndex + neutralIndex));
		    	var blueIndex = 0;
			//////////////////////////////////////////////////////
		    	ctx.fillStyle = "rgb(" + redIndex + "," + greenIndex  + "," + blueIndex + ")";          
		    	ctx.fill();
		    	
		    	// node halo calcluation
		    	var activeIndex = node.getData('activeIndex');
	
		    	for (var i = 0; i < activeIndex; i++){  
		    		ctx.beginPath(); 
		    		ctx.arc(x, y, dim + 1.5 + i / 1.5 , 0, Math.PI * 2, true);
		    		ctx.strokeStyle = custom.haloBaseColor +(activeIndex - i)/10+')';  
		    		ctx.stroke();
		    	}
		    },
		    'contains': function(node, pos){
		    	var npos = node.pos.getc(true), 
		    		dim = node.getData('dim');
		    	return this.nodeHelper.circle.contains(npos, pos, dim);
		    }
	    }   
    }); 

var Guide = {
  elem: false,
  write: function(text){
    if (!this.elem) 
      this.elem = document.getElementById('network-guide');
    this.elem.innerHTML = text;
    this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
  }
};
	
    // Global variables for the selected nodes
    var selectedCounter = 0,
        previousSelectedNode1,
        previousSelectedNode2,
        rootNode;

    // init ForceDirected
    var fd = new $jit.ForceDirected({
	    //id of the visualization container
	    injectInto: containerId,
	    //Number of iterations for the FD algorithm
	    iterations: custom.FDIterations,
	    //Edge length
	    levelDistance: custom.edgeDistance,
		
	    //Enable zooming and panning
	    //with scrolling and DnD
	    Navigation: {
		    enable: true,
		    //Enable panning events only if we're dragging the empty
		    //canvas (and not a node).
		    panning: 'avoid nodes',
		    zooming: custom.zoomSpeed //zoom speed. higher is more sensible
	    },
		
	    // Change node and edge styles such as
	    // color and width.
	    // These properties are also set per node
	    // with dollar prefixed data-properties in the
	    // JSON structure.
	    Node: {
            overridable: true,
            dim: custom.nodeDim,
			type: custom.nodeStyle
		},
			
		Edge: {
			overridable: true,
		    color: custom.edgeColor,
			lineWidth: custom.edgeWidth
		},
			
		// Add node events
		Events: {
		    enable: true,
		    enableForEdges: true,
		    type: 'Native',

			//Change cursor style when hovering a node
			onMouseEnter: function() {
				fd.canvas.getElement().style.cursor = 'move';
			},
			onMouseLeave: function() {
				fd.canvas.getElement().style.cursor = '';
			},

			//Update node positions when dragged
			onDragMove: function(node, eventInfo, e) {
				var pos = eventInfo.getPos();
				node.pos.setc(pos.x, pos.y);
				fd.plot();
			},
			
			//Implement the same handler for touchscreens
			onTouchMove: function(node, eventInfo, e) {
				$jit.util.event.stop(e); //stop default touchmove event
				this.onDragMove(node, eventInfo, e);
			},
					
			// Highlight the edge when clicked on it
			onClick: function(node, eventInfo, e){
			    if(custon.type == "paper"){
    				if(node.nodeFrom){
    					// Build the right column relations list.
    					// This is done by traversing the clicked node connections.
    					var nodeList = [];
		
    					//set final styles
    					fd.graph.eachNode(function(n) {
    						n.eachAdjacency(function(adj) {
    						    if(adj.id != node.id) 
    						        delete adj.selected;
    							adj.setDataset('end', {
    					    		lineWidth: custom.edgeWidth,
    								color: custom.edgeColor
    							});
    						});
    					});
				 
    					// highlight the selected node and display the names of the nodes connected by it
    					if(!node.selected) {
    						node.selected = true;
    						//window.alert("edges - node1: " + node.nodeTo.getData("personId"));
    						//window.alert("edges - node2: " + node.nodeFrom.getData("personId"));
    						nodeList.push(node.nodeTo.getData("personId"));
    						nodeList.push(node.nodeFrom.getData("personId"));
    						node.setDataset('end', {
    							lineWidth: custom.edgeSelectedWidth,
    							color: custom.edgeSelectedColor
    						});
    
    					} else {
    						delete node.selected;
    					}
    					

    					//trigger animation to final styles
					    fd.fx.animate({
    						modes: ['node-property:dim',
    								'edge-property:lineWidth:color'],
    						duration: 500
    					});
    
    					// call "callback(people)" where people is an array of people ids of any length [21,24,35]
    					//window.alert(nodeList[0] + ", " + nodeList[1] + ", " + nodeList[2]);
    					callback(nodeList); 
    				}
    			}
			}
	    },
	    
	    // Called only in person view
	    onBeforeCompute: function (node){
	        if(custom.type == "person"){
                    if(node.id == "_root_"){
                        rootNode = node;
                        node.setData('dim', 17, 'end');

                        //trigger animation to final styles
                        fd.fx.animate({
                            modes: ['node-property:dim'],
                            duration: 0
                        });
                    }
                }
            },

            // This method is only triggered
            // on label creation and only for DOM labels (not native canvas ones).
            onCreateLabel: function(domElement, node){
            // Create a 'name' button and add it to the main node label

		    var nameContainer = document.createElement('span'),C
			    style = nameContainer.style;
	        nameContainer.className = 'name';
	        nameContainer.innerHTML = node.name;
	        domElement.appendChild(nameContainer);
	        style.fontSize = custom.labelFontSize;
	        style.color = custom.labelColor;

	        //Toggle a node selection when clicking
	        //its name. This is done by animating some
	        //node styles like its dimension and the color
	        //and lineWidth of its adjacencies.
	        nameContainer.onclick = function() {
	            var nodeList = [];
	            if(custom.type == "paper"){
		            selectedCounter++;
		            var cases = 0;

		            // after clicking, there should be only one selected node
		            if(selectedCounter == 1){
			            cases = 2;
			            previousNode1 = node;
			            previousNode2 = null;
		            } else {    //selectedCounter > 1
			            fd.graph.eachNode(function(n) {
			
				            // the 2nd click when there is a node already be selected
				            if(selectedCounter == 2){
					            if(node == previousNode1){
						            previousNode1 = null;
						            previousNode2 = null;
						            selectedCounter = 0;
					            } else if(n.id == node.id){
						            previousNode2 = node;
						            cases = 3;
					            }
				            }
					
				            // two nodes have been selected before the 3rd clicking 
				            if(selectedCounter == 3){
					            selectedCounter = 1;
					            if(node.id == previousNode1.id){
						            delete n.selected;
					            previousNode1 = previousNode2;
					            previousNode2 = null;
					            cases = 1;
					            } else if(node.id == previousNode2.id){
						            delete n.selected;
						            previousNode2 = null;
						            cases = 1;
					            } else {
						            previousNode1 = node;
						            previousNode2 = null;
						            delete n.selected;       
						            cases = 2;     
					            }
				            }

				            // draw ordinary nodes
				            n.setData('dim', 7, 'end');
				            n.eachAdjacency(function(adj) {
					            adj.setDataset('end', {
						            lineWidth: custom.edgeWidth,
						            color: custom.edgeColor
						        });
					        });
			            })
		            };

		            var drawSelected = function(drawSelectedNode){
			            drawSelectedNode.selected = true;
    //			        drawSelectedNode.setData('type','square', 'end');
			            drawSelectedNode.eachAdjacency(function(adj) {
				            adj.setDataset('end', {
					            lineWidth: custom.edgeSelectedWidth,
					            color: custom.edgeSelectedColor
				            });
				        });
			        };

		            // draw selected nodes
		            switch(cases){
		            case 1:
			            drawSelected(previousNode1);
			            //window.alert("case1 - name: " + perviousNode1.getData("personId"));
			            nodeList.push(previousNode1.getData("personId"));
			            break;
		            case 2:
			            drawSelected(node);
			            //window.alert("case 2 - name: " + node.getData("personId"));
			            nodeList.push(node.getData("personId"));
			            break;
		            case 3:
			            drawSelected(previousNode1);
			            drawSelected(previousNode2);
			            //window.alert("case 3 - name1: " + previousNode1.getData("personId"));
			            //window.alert("case 3 - name2: " + previousNode2.getData("personId"));
			            nodeList.push(previousNode1.getData("personId"));
			            nodeList.push(previousNode2.getData("personId"));
			            break;
		            }
                }
                
                
                else if (custom.type == "person"){
                    if(node.id != "_root_"){
                        //set final styles
                        fd.graph.eachNode(function(n) {
                            if(n.id != node.id) delete n.selected;
                            n.setData('dim', 7, 'end');
                            n.eachAdjacency(function(adj) {
                                adj.setDataset('end', {
                                    lineWidth: custom.edgeWidth,
                                    color: custom.edgeColor
                                });
                            });
                        });
                    }
                
                    nodeList.push(rootNode.getData("personId"));
                
                    if(!node.selected && node.id != "_root_") {
                        nodeList.push(node.getData("personId"));
                        node.selected = true;
                        rootNode.setData('dim', 17, 'end');
                  
                        node.eachAdjacency(function(adj) {
                            if (adj.nodeTo.id == "_root_" || adj.nodeFrom.id == "_root_"){
                                adj.setDataset('end', {
                                    lineWidth: custom.edgeSelectedWidth,
                                    color: custom.edgeSelectedColor
                                })
                            };
                        });
                    } else if (node.id != "_root_"){
                        rootNode.setData('dim', 17, 'end');
                        delete node.selected;
                    }
                } 
                
                
		        //trigger animation to final styles
		        fd.fx.animate({
			        modes: ['node-property:dim',
							'edge-property:lineWidth:color'],
			        duration: 500
		        });

		        // call "callback(people)" where people is an array of people ids of any length [21,24,35]
		        //window.alert(nodeList[0] + ", " + nodeList[1] + ", " + nodeList[2]);
		        callback(nodeList);					
	        };
        },

        // Change node styles when DOM labels are placed
        // or moved.
        onPlaceLabel: function(domElement, node){
	        var style = domElement.style;
	        var left = parseInt(style.left);
	        var top = parseInt(style.top);
	        var w = domElement.offsetWidth;
	        style.left = (left - w / 2) + 'px';
	        style.top = (top + 10) + 'px';
	        style.display = '';
	    }
    });
	
	this.update = function(data) {
		// load JSON data.
		fd.loadJSON(data);
		
		// compute positions incrementally and animate.
		fd.computeIncremental({
			iter: 40,
			property: 'end',
			onComplete: function(){
                                //Guide.write('<a href="#" class="button" onclick="javascript:showElement('collapse')"><span>Network Guidance</span></a><ul id="collapse" class="collapse" style="display:none;"><b>How to use the network</b></br><li>Click on the name of people or the edge to filter the conversation and the time chart.</li><li>Drag nodes, move the whole graph, or use the middle button on the mouse to zoom</li><br/><b>What is the meaning of the shape of the nodes</b><br /><li>Color - general sentiment attitude of this person</li><li>Size - the number of paper the person has reviewed</li><li>Halo - active index of the people recently</li></ul>');
								//Guide.write('<ul id="collapse" class="collapse" style="display:none;"><b>How to use the network</b></br><li>Click on the name of people or the edge to filter the conversation and the time chart.</li><li>Drag nodes, move the whole graph, or use the middle button on the mouse to zoom</li><br/><b>What is the meaning of the shape of the nodes</b><br /><li>Color - general sentiment attitude of this person</li><li>Size - the number of paper the person has reviewed</li><li>Halo - active index of the people recently</li>');
				fd.animate({
					modes: ['linear'],
					transition: $jit.Trans.Elastic.easeOut,
								duration: 2500
				});
			}
		});
	}
}

//I think this should go in the 'system.js' file if we're going to use it in other places - Adam
function showElement(layer)
{//to collapse html element, now only use to collapse and expand network guidance
	var myLayer = document.getElementById(layer);
	
	if(myLayer.style.display=="none"){
		myLayer.style.display="block";
		myLayer.backgroundPosition="top";
	} 
	else {
		myLayer.style.display="none";
	}
}
